package com.borqsprocessmanager.view;

import java.util.ArrayList;
import java.util.WeakHashMap;

import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Pair;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
import android.widget.CompoundButton;

import com.borqsprocessmanager.R;
import com.borqsprocessmanager.util.Log;
import com.borqsprocessmanager.view.MagicButton.Shadow;

public class MySwitch extends CompoundButton {
    private static final String TAG = "MySwitch";
    private static final int TOUCH_MODE_IDLE = 0;
    private static final int TOUCH_MODE_DOWN = 1;
    private static final int TOUCH_MODE_DRAGGING = 2;

    // Enum for the "typeface" XML parameter.
    private static final int SANS = 1;
    private static final int SERIF = 2;
    private static final int MONOSPACE = 3;

    private Canvas tempCanvas;
    private Bitmap tempBitmap;
    private Drawable mThumbDrawable;
    private Drawable mTrackDrawable;
    private int mThumbTextPadding;
    private int mSwitchMinWidth;
    private int mSwitchPadding;
    private int mTextColor;
    private int mOuterShadowColor;
    private int mCheckedTextColor;
    private int mCurrentTextColor;

    private CharSequence mTextOn;
    private CharSequence mTextOff;

    private CharSequence mTextOnCaption;
    private CharSequence mTextOffCaption;

    private int mTouchMode;
    private int mTouchSlop;
    private float mTouchX;
    private float mTouchY;
    private VelocityTracker mVelocityTracker = VelocityTracker.obtain();
    private int mMinFlingVelocity;

    private float mThumbPosition;
    private int mSwitchWidth;
    private int mSwitchHeight;
    private int mThumbWidth; // Does not include padding

    private int mSwitchLeft;
    private int mSwitchTop;
    private int mSwitchRight;
    private int mSwitchBottom;

    private float strokeWidth;
    private int mStrokeColor;
    private int mCheckedStrokeColor;
    private int mCurrentStrokeColor;
    private Join strokeJoin;
    private float strokeMiter;

    private ArrayList<Shadow> outerShadows;
    private ArrayList<Shadow> innerShadows;
    private WeakHashMap<String, Pair<Canvas, Bitmap>> canvasStore;

    private TextPaint mTextPaint;
    private ColorStateList mTextColors;
    private Layout mOnLayout;
    private Layout mOffLayout;

    private Context mContext;

    @SuppressWarnings("hiding")
    private final Rect mTempRect = new Rect();

    private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };

    /**
     * Construct a new Switch with default styling.
     * 
     * @param context
     *            The Context that will determine this widget's theming.
     */
    public MySwitch(Context context) {
        this(context, null);

        mContext = context;
    }

    /**
     * Construct a new Switch with default styling, overriding specific style
     * attributes as requested.
     * 
     * @param context
     *            The Context that will determine this widget's theming.
     * @param attrs
     *            Specification of attributes that should deviate from default
     *            styling.
     */
    public MySwitch(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.switchStyle);

        mContext = context;
    }

    /**
     * Construct a new Switch with a default style determined by the given theme
     * attribute, overriding specific style attributes as requested.
     * 
     * @param context
     *            The Context that will determine this widget's theming.
     * @param attrs
     *            Specification of attributes that should deviate from the
     *            default styling.
     * @param defStyle
     *            An attribute ID within the active theme containing a reference
     *            to the default style for this widget. e.g.
     *            android.R.attr.switchStyle.
     */
    public MySwitch(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        mContext = context;

        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        final Resources res = getResources();
        mTextPaint.density = res.getDisplayMetrics().density;

        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.Switch, defStyle, 0);

        initTextViewPaint(a);

        mThumbDrawable = a.getDrawable(R.styleable.Switch_thumb);
        mTrackDrawable = a.getDrawable(R.styleable.Switch_track);
        mTextOn = a.getText(R.styleable.Switch_textOn);
        mTextOff = a.getText(R.styleable.Switch_textOff);
        mThumbTextPadding = a.getDimensionPixelSize(
                R.styleable.Switch_thumbTextPadding, 0);
        mSwitchMinWidth = a.getDimensionPixelSize(
                R.styleable.Switch_switchMinWidth, 0);
        mSwitchPadding = a.getDimensionPixelSize(
                R.styleable.Switch_switchPadding, 0);

        Log.v("SvenDebug", "mTextOn:" + mTextOn);
        Log.v("SvenDebug", "mTextOff:" + mTextOff);
        Log.v("SvenDebug", "mThumbTextPadding:" + mThumbTextPadding);
        Log.v("SvenDebug", "mSwitchMinWidth:" + mSwitchMinWidth);
        Log.v("SvenDebug", "mSwitchPadding:" + mSwitchPadding);

        int appearance = a.getResourceId(
                R.styleable.Switch_switchTextAppearance, 0);
        if (appearance != 0) {
            // setSwitchTextAppearance(context, appearance);
        }
        a.recycle();

        ViewConfiguration config = ViewConfiguration.get(context);
        mTouchSlop = config.getScaledTouchSlop();
        mMinFlingVelocity = config.getScaledMinimumFlingVelocity();

        // Refresh display with current params
        refreshDrawableState();
        setChecked(isChecked());
    }

    public void init(AttributeSet attrs) {

    }

    private TextPaint initTextViewPaint(TypedArray a) {
        outerShadows = new ArrayList<Shadow>();
        innerShadows = new ArrayList<Shadow>();
        if (canvasStore == null) {
            canvasStore = new WeakHashMap<String, Pair<Canvas, Bitmap>>();
        }

        String typefaceName = a.getString(R.styleable.MagicTextView_typeface);
        if (typefaceName != null) {
            Typeface tf = Typeface.createFromAsset(getContext().getAssets(),
                    String.format("fonts/%s.ttf", typefaceName));
            setTypeface(tf);
        }

        if (a.hasValue(R.styleable.MagicTextView_innerShadowColor)) {
            addInnerShadow(a.getDimension(
                    R.styleable.MagicTextView_innerShadowRadius, 0),
                    a.getDimension(R.styleable.MagicTextView_innerShadowDx, 0),
                    a.getDimension(R.styleable.MagicTextView_innerShadowDy, 0),
                    a.getColor(R.styleable.MagicTextView_innerShadowColor,
                            0xff000000));
        }

        if (a.hasValue(R.styleable.MagicTextView_outerShadowColor)) {
            addOuterShadow(a.getDimension(
                    R.styleable.MagicTextView_outerShadowRadius, 0),
                    a.getDimension(R.styleable.MagicTextView_outerShadowDx, 0),
                    a.getDimension(R.styleable.MagicTextView_outerShadowDy, 0),
                    a.getColor(R.styleable.MagicTextView_outerShadowColor,
                            0xff000000));
        }
        if (a.hasValue(R.styleable.MagicTextView_strokeColor)) {
            float strokeWidth = a.getDimension(
                    R.styleable.MagicTextView_strokeWidth, 1);
            int strokeColor = a.getColor(R.styleable.MagicTextView_strokeColor,
                    0xff000000);
            float strokeMiter = a.getDimension(
                    R.styleable.MagicTextView_strokeMiter, 10);
            Join strokeJoin = null;
            switch (a.getInt(R.styleable.MagicTextView_strokeJoinStyle, 0)) {
            case (0):
                strokeJoin = Join.MITER;
                break;
            case (1):
                strokeJoin = Join.BEVEL;
                break;
            case (2):
                strokeJoin = Join.ROUND;
                break;
            }

            this.setStroke(strokeWidth, strokeColor, strokeJoin, strokeMiter);
        }

        // final CompatibilityInfo compat = res.getCompatibilityInfo();

        if (a.hasValue(R.styleable.Switch_switchTextColor)) {
            mTextColor = a.getColor(R.styleable.Switch_switchTextColor, 0);
        }

        // if (a.hasValue(R.styleable.Switch_checkedSwitchTextColor)) {
        mCheckedTextColor = a.getColor(
                R.styleable.Switch_checkedSwitchTextColor, mTextColor);
        // }

        // if (a.hasValue(R.styleable.Switch_checkedStrokeColor)) {
        mCheckedStrokeColor = a.getColor(R.styleable.Switch_checkedStrokeColor,
                mStrokeColor);
        // }

        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        // mTextPaint.setStyle(Style.STROKE);
        // mTextPaint.setStrokeJoin(strokeJoin);
        // mTextPaint.setStrokeMiter(strokeMiter);
        // this.setTextColor(strokeColor);
        // mTextPaint.setStrokeWidth(strokeWidth);
        // // super.onDraw(canvas);
        // mTextPaint.setColor(mTextColor);

        mTextPaint.setTextSize(getTextSize());
        Log.v("initTextViewPaint", "mTextColor:" + mTextColor);
        Log.v("initTextViewPaint", "mOuterShadowColor:" + mOuterShadowColor);
        return mTextPaint;
    }

    /**
     * Sets the switch text color, size, style, hint color, and highlight color
     * from the specified TextAppearance resource.
     */
    // public void setSwitchTextAppearance(Context context, int resid) {
    // mContext = context;
    //
    // TypedArray appearance = context.obtainStyledAttributes(resid,
    // R.styleable.TextAppearance);
    //
    // ColorStateList colors;
    // int ts;
    //
    // colors = appearance
    // .getColorStateList(R.styleable.TextAppearance_textColor);
    // if (colors != null) {
    // mTextColors = colors;
    // } else {
    // // If no color set in TextAppearance, default to the view's
    // // textColor
    // mTextColors = getTextColors();
    // }
    //
    // ts = appearance.getDimensionPixelSize(
    // R.styleable.TextAppearance_textSize, 0);
    // if (ts != 0) {
    // if (ts != mTextPaint.getTextSize()) {
    // mTextPaint.setTextSize(ts);
    // requestLayout();
    // }
    // }
    //
    // int typefaceIndex, styleIndex;
    //
    // typefaceIndex = appearance.getInt(R.styleable.TextAppearance_typeface,
    // -1);
    // styleIndex = appearance
    // .getInt(R.styleable.TextAppearance_textStyle, -1);
    //
    // setSwitchTypefaceByIndex(typefaceIndex, styleIndex);
    //
    // appearance.recycle();
    // }

    private void setSwitchTypefaceByIndex(int typefaceIndex, int styleIndex) {
        Typeface tf = null;
        switch (typefaceIndex) {
        case SANS:
            tf = Typeface.SANS_SERIF;
            break;

        case SERIF:
            tf = Typeface.SERIF;
            break;

        case MONOSPACE:
            tf = Typeface.MONOSPACE;
            break;
        }

        setSwitchTypeface(tf, styleIndex);
    }

    /**
     * Sets the typeface and style in which the text should be displayed on the
     * switch, and turns on the fake bold and italic bits in the Paint if the
     * Typeface that you provided does not have all the bits in the style that
     * you specified.
     */
    public void setSwitchTypeface(Typeface tf, int style) {
        if (style > 0) {
            if (tf == null) {
                tf = Typeface.defaultFromStyle(style);
            } else {
                tf = Typeface.create(tf, style);
            }
            setSwitchTypeface(tf);
            // now compute what (if any) algorithmic styling is needed
            int typefaceStyle = tf != null ? tf.getStyle() : 0;
            int need = style & ~typefaceStyle;
            mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0);
            mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0);
        } else {
            mTextPaint.setFakeBoldText(false);
            mTextPaint.setTextSkewX(0);
            setSwitchTypeface(tf);
        }
    }

    /**
     * Sets the typeface in which the text should be displayed on the switch.
     * Note that not all Typeface families actually have bold and italic
     * variants, so you may need to use
     * {@link #setSwitchTypeface(Typeface, int)} to get the appearance that you
     * actually want.
     * 
     * @attr ref android.R.styleable#TextView_typeface
     * @attr ref android.R.styleable#TextView_textStyle
     */
    public void setSwitchTypeface(Typeface tf) {
        if (mTextPaint.getTypeface() != tf) {
            mTextPaint.setTypeface(tf);

            requestLayout();
            invalidate();
        }
    }

    /**
     * Returns the text displayed when the button is in the checked state.
     */
    public CharSequence getTextOn() {
        return mTextOn;
    }

    /**
     * Sets the text displayed when the button is in the checked state.
     */
    public void setTextOn(CharSequence textOn) {
        mTextOn = textOn;
        requestLayout();
    }

    /**
     * Returns the text displayed when the button is not in the checked state.
     */
    public CharSequence getTextOff() {
        return mTextOff;
    }

    /**
     * Sets the text displayed when the button is not in the checked state.
     */
    public void setTextOff(CharSequence textOff) {
        mTextOff = textOff;
        requestLayout();
    }

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        if (mOnLayout == null) {
            mOnLayout = makeLayout(mTextOn);
        }
        if (mOffLayout == null) {
            mOffLayout = makeLayout(mTextOff);
        }

        mTrackDrawable.getPadding(mTempRect);
        // final int maxTextWidth = Math.max(mOnLayout.getWidth(),
        // mOffLayout.getWidth());
        // final int switchWidth = Math.max(mSwitchMinWidth, maxTextWidth * 2
        // 原生为text通过text宽度计算
        // + mThumbTextPadding * 4 + mTempRect.left + mTempRect.right);

        final int trackDrawableWidth = mTrackDrawable.getIntrinsicWidth();
        final int trackDrawableHeight = mTrackDrawable.getIntrinsicHeight();

        // final int switchWidth = mTrackDrawable.getIntrinsicWidth();
        // final int switchHeight = mTrackDrawable.getIntrinsicHeight();

        // final int switchWidth = widthSize;
        // final int switchHeight = widthSize;

        // mThumbWidth = maxTextWidth + mThumbTextPadding * 2;

        switch (widthMode) {
        case MeasureSpec.AT_MOST:
            mSwitchWidth = Math.min(widthSize, trackDrawableWidth);

            Log.v(TAG, "widthMode_AT_MOST===" + mSwitchWidth);
            break;

        case MeasureSpec.UNSPECIFIED:
            mSwitchWidth = trackDrawableWidth;
            Log.v(TAG, "widthMode_UNSPECIFIED===" + mSwitchWidth);
            break;

        case MeasureSpec.EXACTLY:
            mSwitchWidth = widthSize;
            Log.v(TAG, "widthMode_EXACTLY===" + mSwitchWidth);
            break;
        }

        switch (heightMode) {
        case MeasureSpec.AT_MOST:
            mSwitchHeight = Math.min(heightSize, trackDrawableHeight);
            Log.v(TAG, "heightMode_AT_MOST===" + mSwitchHeight);
            break;

        case MeasureSpec.UNSPECIFIED:
            mSwitchHeight = trackDrawableHeight;
            Log.v(TAG, "heightMode_UNSPECIFIED===" + mSwitchWidth);
            break;

        case MeasureSpec.EXACTLY:
            mSwitchHeight = heightSize;
            Log.v(TAG, "heightMode_EXACTLY===" + mSwitchHeight);
            break;
        }
        mThumbWidth = mThumbDrawable.getIntrinsicWidth();// 变为图片大小
        // mSwitchWidth = resolveSize(trackDrawableWidth, widthMeasureSpec);
        // mSwitchHeight = resolveSize(trackDrawableHeight,
        // heightMeasureSpec);

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        final int measuredHeight = getMeasuredHeight();
        if (measuredHeight < trackDrawableHeight) {
            setMeasuredDimension(getMeasuredWidth(), trackDrawableHeight);
        }
    }

    /*
     * @Override public boolean dispatchTouchEvent(MotionEvent event) {
     * Log.d("SvenDebug", "dispatchTouchEvent:action=" + event.getAction());
     * return false; }
     */

    @Override
    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
        Log.v("SvenDebug", "dispatchPopulateAccessibilityEvent");
        populateAccessibilityEvent(event);

        return false;
    }

    public void populateAccessibilityEvent(AccessibilityEvent event) {
        if (isChecked()) {
            CharSequence text = mOnLayout.getText();
            if (TextUtils.isEmpty(text)) {
                text = mContext.getString(R.string.switch_on);
            }
            event.getText().add(text);
        } else {
            CharSequence text = mOffLayout.getText();
            if (TextUtils.isEmpty(text)) {
                text = mContext.getString(R.string.switch_off);
            }
            event.getText().add(text);
        }
    }

    private Layout makeLayout(CharSequence text) {
        return new StaticLayout(text, mTextPaint, (int) Math.ceil(Layout
                .getDesiredWidth(text, mTextPaint)),
                Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true);
    }

    /**
     * @return true if (x, y) is within the target area of the switch thumb
     */
    private boolean hitThumb(float x, float y) {
        mThumbDrawable.getPadding(mTempRect);
        final int thumbTop = mSwitchTop - mTouchSlop;
        final int thumbLeft = mSwitchLeft + (int) (mThumbPosition + 0.5f)
                - mTouchSlop;
        final int thumbRight = thumbLeft + mThumbWidth + mTempRect.left
                + mTempRect.right + mTouchSlop;
        final int thumbBottom = mSwitchBottom + mTouchSlop;
        return x > thumbLeft && x < thumbRight && y > thumbTop
                && y < thumbBottom;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        mVelocityTracker.addMovement(ev);
        final int action = ev.getActionMasked();
        Log.v("SvenDebug", "MotionEvent : " + action);
        switch (action) {
        case MotionEvent.ACTION_DOWN: {
            Log.v("SvenDebug", "MotionEvent.ACTION_DOWN");
            final float x = ev.getX();
            final float y = ev.getY();
            if (isEnabled() && hitThumb(x, y)) {
                Log.v("SvenDebug", "Enable in widget rect");
                mTouchMode = TOUCH_MODE_DOWN;
                mTouchX = x;
                mTouchY = y;
            }
            break;
        }

        case MotionEvent.ACTION_MOVE: {
            Log.v("SvenDebug", "MotionEvent.ACTION_MOVE");
            switch (mTouchMode) {
            case TOUCH_MODE_IDLE:
                // Didn't target the thumb, treat normally.
                break;

            case TOUCH_MODE_DOWN: {
                Log.v("SvenDebug", "TOUCH_MODE_DOWN:mTouchSlop = " + mTouchSlop);
                final float x = ev.getX();
                final float y = ev.getY();
                if (Math.abs(x - mTouchX) > mTouchSlop
                        || Math.abs(y - mTouchY) > mTouchSlop) {
                    mTouchMode = TOUCH_MODE_DRAGGING;
                    getParent().requestDisallowInterceptTouchEvent(true);
                    mTouchX = x;
                    mTouchY = y;
                    return true;
                }
                break;
            }

            case TOUCH_MODE_DRAGGING: {
                Log.v("SvenDebug", "TOUCH_MODE_DRAGGING");
                final float x = ev.getX();
                final float dx = x - mTouchX;
                float newPos = Math.max(0,
                        Math.min(mThumbPosition + dx, getThumbScrollRange()));
                if (newPos != mThumbPosition) {
                    mThumbPosition = newPos;
                    mTouchX = x;
                    invalidate();
                }
                return true;
            }
            }
            break;
        }

        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL: {
            Log.v("SvenDebug", "MotionEvent.ACTION_UP|ACTION_CANCEL");
            if (mTouchMode == TOUCH_MODE_DRAGGING) {
                stopDrag(ev);
                return true;
            }
            mTouchMode = TOUCH_MODE_IDLE;
            mVelocityTracker.clear();
            break;
        }
        }

        return super.onTouchEvent(ev);
    }

    private void cancelSuperTouch(MotionEvent ev) {
        MotionEvent cancel = MotionEvent.obtain(ev);
        cancel.setAction(MotionEvent.ACTION_CANCEL);
        super.onTouchEvent(cancel);
        cancel.recycle();
    }

    /**
     * Called from onTouchEvent to end a drag operation.
     * 
     * @param ev
     *            Event that triggered the end of drag mode - ACTION_UP or
     *            ACTION_CANCEL
     */
    private void stopDrag(MotionEvent ev) {
        mTouchMode = TOUCH_MODE_IDLE;
        // Up and not canceled, also checks the switch has not been disabled
        // during the drag
        boolean commitChange = ev.getAction() == MotionEvent.ACTION_UP
                && isEnabled();

        cancelSuperTouch(ev);

        if (commitChange) {
            boolean newState;
            mVelocityTracker.computeCurrentVelocity(1000);
            float xvel = mVelocityTracker.getXVelocity();
            if (Math.abs(xvel) > mMinFlingVelocity) {
                newState = xvel > 0;
            } else {
                newState = getTargetCheckedState();
            }
            animateThumbToCheckedState(newState);
        } else {
            animateThumbToCheckedState(isChecked());
        }
    }

    private void animateThumbToCheckedState(boolean newCheckedState) {
        // TODO animate!
        // float targetPos = newCheckedState ? 0 : getThumbScrollRange();
        // mThumbPosition = targetPos;
        setChecked(newCheckedState);
    }

    private boolean getTargetCheckedState() {
        return mThumbPosition >= getThumbScrollRange() / 2;
    }

    @Override
    public void setChecked(boolean checked) {
        super.setChecked(checked);
        mThumbPosition = checked ? getThumbScrollRange() : 0;
        invalidate();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right,
            int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        mThumbPosition = isChecked() ? getThumbScrollRange() : 0;

        int switchRight = getWidth() - getPaddingRight();
        int switchLeft = switchRight - mSwitchWidth;
        int switchTop = 0;
        int switchBottom = 0;
        switch (getGravity() & Gravity.VERTICAL_GRAVITY_MASK) {
        default:
        case Gravity.TOP:
            switchTop = getPaddingTop();
            switchBottom = switchTop + mSwitchHeight;
            break;

        case Gravity.CENTER_VERTICAL:
            switchTop = (getPaddingTop() + getHeight() - getPaddingBottom())
                    / 2 - mSwitchHeight / 2;
            switchBottom = switchTop + mSwitchHeight;
            break;

        case Gravity.BOTTOM:
            switchBottom = getHeight() - getPaddingBottom();
            switchTop = switchBottom - mSwitchHeight;
            break;
        }

        mSwitchLeft = switchLeft;
        mSwitchTop = switchTop;
        mSwitchBottom = switchBottom;
        mSwitchRight = switchRight;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // Draw the switch
        int switchLeft = mSwitchLeft;
        int switchTop = mSwitchTop;
        int switchRight = mSwitchRight;
        int switchBottom = mSwitchBottom;

        mTrackDrawable.setBounds(switchLeft, switchTop, switchRight,
                switchBottom);
        mTrackDrawable.draw(canvas);

        canvas.save();

        mTrackDrawable.getPadding(mTempRect);
        int switchInnerLeft = switchLeft + mTempRect.left;
        int switchInnerTop = switchTop + mTempRect.top;
        int switchInnerRight = switchRight - mTempRect.right;
        int switchInnerBottom = switchBottom - mTempRect.bottom;
        canvas.clipRect(switchInnerLeft, switchTop, switchInnerRight,
                switchBottom);

        // FIXME:
        // Drawable offDrawable =
        // mContext.getResources().getDrawable(R.drawable.switch_thumb_mz);
        // Drawable onDrawable =
        //
        // mContext.getResources().getDrawable(
        // R.drawable.switch_thumb_activated_mz);
        // mThumbDrawable = getTargetCheckedState() ? onDrawable : offDrawable;

        mThumbDrawable.getPadding(mTempRect);
        final int thumbPos = (int) (mThumbPosition + 0.5f);
        int thumbLeft = switchInnerLeft - mTempRect.left + thumbPos;
        int thumbRight = switchInnerLeft + thumbPos + mThumbWidth
                + mTempRect.right;

        mThumbDrawable
                .setBounds(thumbLeft, switchTop, thumbRight, switchBottom);

        // mTextColors should not be null, but just in case
        // if (mTextColors != null) {
        // mTextPaint.setColor(mTextColors.getColorForState(
        // getDrawableState(), mTextColors.getDefaultColor()));
        // }
        // mTextPaint.drawableState = getDrawableState();

        // Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout;
        Layout switchText;
        if (getTargetCheckedState()) {
            switchText = mOnLayout;
            mCurrentTextColor = mTextColor;
            mCurrentStrokeColor = mStrokeColor;
           
        } else {
            switchText = mOffLayout;
            mCurrentTextColor = mCheckedTextColor;
            mCurrentStrokeColor = mCheckedStrokeColor;
        }
        outerShadows.get(0).color=mCurrentTextColor;
        int switch2 = (switchInnerLeft + switchInnerRight);

        int startX2 = (switch2 - switchText.getWidth()) / 2
                - (switch2 - (thumbRight - thumbLeft)) / 4;
        canvas.translate(
                startX2 + ((switch2 - thumbRight) / 2),
                (switchInnerTop + switchInnerBottom) / 2
                        - switchText.getHeight() / 2);

        drawText(switchText, canvas);
        canvas.restore();
        mThumbDrawable.draw(canvas);
    }

    private void drawText(Layout switchText, Canvas canvas) {

        // this.setCompoundDrawables(null, null, null, null);

        for (Shadow shadow : outerShadows) {
            mTextPaint.setShadowLayer(shadow.r, shadow.dx, shadow.dy,
                    shadow.color);
            switchText.draw(canvas);
        }
        mTextPaint.setShadowLayer(0, 0, 0, 0);

        if (mCurrentTextColor != 0) {
            mTextPaint.setStyle(Style.STROKE);
            mTextPaint.setStrokeJoin(strokeJoin);
            mTextPaint.setStrokeMiter(strokeMiter);
            mTextPaint.setColor(mCurrentStrokeColor);
            mTextPaint.setStrokeWidth(strokeWidth);
            switchText.draw(canvas);
            mTextPaint.setStyle(Style.FILL);
            mTextPaint.setColor(mCurrentTextColor);
            mTextPaint.setStrokeWidth(0);
            switchText.draw(canvas);
        }
    }

    @Override
    public int getCompoundPaddingRight() {
        int padding = super.getCompoundPaddingRight() + mSwitchWidth;
        if (!TextUtils.isEmpty(getText())) {
            padding += mSwitchPadding;
        }
        return padding;
    }

    private int getThumbScrollRange() {
        if (mTrackDrawable == null) {
            return 0;
        }
        mTrackDrawable.getPadding(mTempRect);
        return mSwitchWidth - mThumbWidth - mTempRect.left - mTempRect.right;
    }

    @Override
    protected int[] onCreateDrawableState(int extraSpace) {
        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
        if (isChecked()) {
            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
        }
        return drawableState;
    }

    @Override
    protected void drawableStateChanged() {
        super.drawableStateChanged();

        int[] myDrawableState = getDrawableState();

        // Set the state of the Drawable
        // Drawable may be null when checked state is set from XML, from super
        // constructor
        if (mThumbDrawable != null)
            mThumbDrawable.setState(myDrawableState);
        if (mTrackDrawable != null)
            mTrackDrawable.setState(myDrawableState);

        invalidate();
    }

    @Override
    protected boolean verifyDrawable(Drawable who) {
        return super.verifyDrawable(who) || who == mThumbDrawable
                || who == mTrackDrawable;
    }

    /*
     * @Override public void jumpDrawablesToCurrentState() {
     * super.jumpDrawablesToCurrentState(); mThumbDrawable.jumpToCurrentState();
     * mTrackDrawable.jumpToCurrentState(); }
     */

    public void addOuterShadow(float r, float dx, float dy, int color) {
        if (r == 0) {
            r = 0.0001f;
        }
        outerShadows.add(new Shadow(r, dx, dy, color));
    }

    public void addInnerShadow(float r, float dx, float dy, int color) {
        if (r == 0) {
            r = 0.0001f;
        }
        innerShadows.add(new Shadow(r, dx, dy, color));
    }

    public void clearInnerShadows() {
        innerShadows.clear();
    }

    public void clearOuterShadows() {
        outerShadows.clear();
    }

    public void setStroke(float width, int color, Join join, float miter) {
        strokeWidth = width;
        mStrokeColor = color;
        strokeJoin = join;
        strokeMiter = miter;
    }

    public void setStroke(float width, int color) {
        setStroke(width, color, Join.MITER, 10);
    }
}
